#ifndef RT_SQLITE3__HPP
#define RT_SQLITE3__HPP

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define SQLITE_HAS_CODEC 1
#include <sqlite3.h>

// define macro
#include <stdbool.h>

// copy from <rtdebug.hpp> [0.2.1]
#define __RT__DEBUG 1
#define nullptr NULL

#define _print(note, ...) \
{	if(__RT__DEBUG) \
    printf("-- DEBUG -->> " note "\n",  ##__VA_ARGS__); }

#define dim(x) (sizeof(x)/sizeof(x[0]))

#define Sqlite3Except jmp_buffer

#include <setjmp.h>
jmp_buf jmp_buffer;
void raise(int err_no, const char* description){
    if(0 == err_no){
        printf("In Function Raise() can't set err_no zero.\n");
        abort();
    }
    if(description){
        if(__RT__DEBUG){
            printf("-- EXCEPT -->> ");
            printf(description);
            printf("\n");
        }
    }
    longjmp(jmp_buffer, err_no);
}

/*-----------------------------------------------------------------*\
    SQLite3 Functions
\*-----------------------------------------------------------------*/

enum ExceptEnum{
    DB_Open_Err = 1,
    DB_Close_Err,
    Exec_Err,
    Select_Err,
    Encrypt_Err,
    Decrypt_Err
};

struct DateBase{
    sqlite3 *pDb;
    sqlite3_stmt *pStmt;
    char*  pErrMsg;  // 仅用于存储 sqlite3_exec() 和 sqlite3_get_table() 的错误信息
    char** pSelect;
};

sqlite3* db_open(const char* file_name, int flags){
    sqlite3 *pDb;
    if(SQLITE_OK != sqlite3_open_v2(file_name, &pDb, flags, NULL)){
        raise(DB_Open_Err, "db_open()");
    }
    return pDb;
}

sqlite3* db_create(const char* file_name){
    return db_open(file_name, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
}

sqlite3* db_open_write(const char* file_name){
    return db_open(file_name, SQLITE_OPEN_READWRITE);
}

sqlite3* db_open_readonly(const char* file_name){
    return db_open(file_name, SQLITE_OPEN_READONLY);
}

void _errmsg_free(char* pErrMsg){
    // 处理通过 sqlite3_exec() 产生的错误信息，由 sqlite3_malloc() 申请，需要手动释放
    if(pErrMsg != nullptr){
        sqlite3_free(pErrMsg);
        // pErrMsg = nullptr;
    }
}

void select_free(char** ppSelect){
    if(ppSelect != nullptr)
        sqlite3_free_table(ppSelect);
}

// 打印Sqlite3错误码
void _errcode(sqlite3 *pDb){
    int code = sqlite3_errcode(pDb);
    printf("SQLite3 错误码 >> %d（%s）\n", code, sqlite3_errstr(code));
}

// 打印Sqlite3错误消息
void db_error(sqlite3 *pDb, char* pErrMsg){
    if(pErrMsg != nullptr){
        printf("SQLite3 错误信息 >> %s\n", pErrMsg);
        _errmsg_free(pErrMsg);
    }else{
        // 一般错误消息, 由SQLite内部管理。其内存将会在下产次调用 sqlite3_errmsg() 时被覆盖
        printf("SQLite3 错误信息 >> %s\n", sqlite3_errmsg(pDb));
    }
}

void db_close(sqlite3 *pDb){
    int status = sqlite3_close(pDb);
    while(SQLITE_BUSY == status){
        sqlite3_stmt *pStmt = sqlite3_next_stmt(pDb, nullptr);  // 查找有效 stmt
        if(pStmt != nullptr){
            status = sqlite3_finalize(pStmt);
            if (status == SQLITE_OK)
                status = sqlite3_close(pDb);
        }else  break;
    }
    if(SQLITE_OK != status){
        raise(DB_Close_Err, "db_close()");
    }
}

void db_exec(sqlite3 *pDb, const char* strSQL, sqlite3_callback pFunc, void *argv){
    char* pErrMsg;
    if(SQLITE_OK != sqlite3_exec(pDb, strSQL, pFunc, argv, &pErrMsg)){
        db_error(pDb, pErrMsg);
        raise(Exec_Err, "db_exec()");
    }
}

char** db_select(sqlite3 *pDb, const char* strSQL, int *row, int *column){
    // 由于函数内 malloc 内存 pSelect，故需要在调用 db_select 后，用 select_free() 释放内存
    char** pSelect;
    char*  pErrMsg;
    if(SQLITE_OK != sqlite3_get_table(pDb, strSQL, &pSelect, row, column, &pErrMsg)){
        db_error(pDb, pErrMsg);
        raise(Select_Err, "db_select()");
    }
    return pSelect;
}
// sqlite3_column_text

#ifdef SQLITE_HAS_CODEC
// return : true >> 加密成功；false >> 数据库已加密；Encrypt_Err >> 加密失败
bool db_lock(sqlite3 *pDb, const char* passwd){
    int status = sqlite3_rekey(pDb, passwd, strlen(passwd));
    if(SQLITE_NOTADB == status){
        // raise(Encrypt_Err, "Database is already encrypted")
        return false;
    }else if(SQLITE_OK != status){
        db_error(pDb, nullptr);
        raise(Encrypt_Err, "db_encrypt()");
    }
    return true;
}

bool db_unlock(sqlite3 *pDb, const char* passwd){
    if(SQLITE_OK != sqlite3_key(pDb, passwd, strlen(passwd))){
        raise(Decrypt_Err, "db_decrypt()");
    }
    return true;
}

bool db_clearkey(sqlite3 *pDb, const char* passwd){
    // 解密当前数据库
    db_unlock(pDb, passwd);
    return SQLITE_OK == sqlite3_rekey(pDb, nullptr, 0);
}

bool db_setkey(sqlite3 *pDb, const char* passwd, const char* new_passwd){
    if(!new_passwd[0]){  // 如 new_passwd 为空，则清除密码
        return db_clearkey(pDb, passwd);
    }
    // 若passwd为空，直接加密
    if(!db_lock(pDb, new_passwd)){
        // 解密当前数据库
        db_unlock(pDb, passwd);
    }
    return db_lock(pDb, new_passwd);
}
#endif // SQLITE_HAS_CODEC

#endif // RT_SQLITE3__HPP
